package com.wbs.cluster.redis.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wbs.cluster.redis.service.RedisSelfService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * TODO redis常用操作接口实现
 */
@Service
public class RedisSelfServiceImpl implements RedisSelfService {

    @Resource(name = "redisPubTemplate")
    private StringRedisTemplate redisTemplate;

    // redis 缓存时效时间
    public static long REDIS_DEF_EXPIRE = 1800;

    @Override
    public boolean set(final String key, final String value) {
        boolean result = redisTemplate.execute((RedisCallback<Boolean>) connection -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            connection.set(serializer.serialize(key), serializer.serialize(value));
            return true;
        });
        return result;
    }

    @Override
    public String get(final String key) {
        String result = redisTemplate.execute((RedisCallback<String>) connection -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            byte[] value = connection.get(serializer.serialize(key));
            return serializer.deserialize(value);
        });
        return result;
    }

    /**
     * 单位是秒
     *
     * @param key
     * @param expire
     * @return
     */
    @Override
    public boolean expire(final String key, long expire) {
        return redisTemplate.expire(key, expire, TimeUnit.SECONDS);
    }

    @Override
    public <T> boolean setList(String key, List<T> list) {
        String value = JSONArray.toJSONString(list);
        return set(key, value);
    }

    @Override
    public <T> List<T> getList(String key, Class<T> clz) {
        String json = get(key);
        if (json != null) {
            List<T> list = JSONArray.parseArray(json, clz);
            return list;
        }
        return null;
    }

    @Override
    public long lpush(final String key, Object obj) {

        final String value;

        if (obj instanceof List) {
            value = JSONArray.toJSONString(obj);
        } else {
            value = JSON.toJSONString(obj);
        }

        long result = redisTemplate.execute((RedisCallback<Long>) connection -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            long count = connection.lPush(serializer.serialize(key), serializer.serialize(value));
            return count;
        });
        return result;
    }

    @Override
    public long rpush(final String key, Object obj) {

        final String value;

        if (obj instanceof List) {
            value = JSONArray.toJSONString(obj);
        } else {
            value = JSON.toJSONString(obj);
        }
        long result = redisTemplate.execute((RedisCallback<Long>) connection -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            long count = connection.rPush(serializer.serialize(key), serializer.serialize(value));
            return count;
        });
        return result;
    }

    @Override
    public String lpop(final String key) {
        String result = redisTemplate.execute((RedisCallback<String>) connection -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            byte[] res = connection.lPop(serializer.serialize(key));
            return serializer.deserialize(res);
        });
        return result;
    }

    @Override
    public void delete(final String key) {
        redisTemplate.delete(key);
    }


    /**
     * 根据key获取素有hash值
     *
     * @param key
     * @return
     */
    @Override
    public List<Object> getValues(String key) {
        List<Object> values = redisTemplate.opsForHash().values(key);
        return values;
    }

    @Override
    public void setHashVal(final String key, final Map<String, String> map) {
        if (redisTemplate.hasKey(key)) {
            redisTemplate.delete(key);
        }
        redisTemplate.opsForHash().putAll(key, map);
    }

    @Override
    public List<String> getHashVal(final String key, final String... value) {

        return redisTemplate.execute((RedisCallback<List<String>>) connection -> {
            List<String> resultList = new ArrayList<>();
            byte[] param = redisTemplate.getStringSerializer().serialize(key);
            // 将String...转为byte[]...
            byte[][] valByte = new byte[value.length][];
            for (int i = 0; i < value.length; i++) {
                valByte[i] = redisTemplate.getStringSerializer().serialize(value[i]);
            }
            if (connection.exists(param)) {
                List<byte[]> dataList = connection.hMGet(param, valByte);
                // 将得到的结果集进行反序列化
                for (byte[] bt : dataList) {
                    resultList.add(redisTemplate.getStringSerializer().deserialize(bt));
                }
            }
            return resultList;
        });
    }

    @Override
    public boolean hasHashKey(String key, String hashKey) {

        if (StringUtils.isBlank(key) || StringUtils.isBlank(hashKey)) {
            return false;
        }
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }

    @Override
    public void delHashValKey(final String key, final Object... hashKeys) {
        if (this.hasHashKey(key, hashKeys.toString())) {
            redisTemplate.opsForHash().delete(key, hashKeys);
        }
    }

    @Override
    public void setHashValKey(final String key, final String hashKey, final String value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    @Override
    public boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    @Override
    public String getHashValStr(String key, String hashKey) {
        if (hasHashKey(key, hashKey)) {
            return redisTemplate.opsForHash().get(key, hashKey).toString();
        } else {
            return "";
        }
    }

    /******|************* 新增方法 ↓↓↓↓↓↓ fengyuan ******************************************************************************************/
    @Override
    public void setRedisExpire(String[] keys, String value, long expireTime) {
        String key = getKey(keys);
        set(key, value);
        expire(key, expireTime);
    }


    @Override
    public void setRedisExpire(String[] keys, String value) {
        String key = getKey(keys);
        set(key, value);
        expire(key, REDIS_DEF_EXPIRE);
    }

    @Override
    public void setRedisExpire(String keys, String value, long expireTime) {
        setRedisExpire(new String[]{keys}, value, expireTime);
    }

    @Override
    public void setRedisExpire(String keys, String value) {
        setRedisExpire(new String[]{keys}, value);
    }

    @Override
    public void setRedisExpire(String[] keys, Object value) {
        setRedisExpire(keys, JSONObject.toJSONString(value));
    }

    @Override
    public void setRedisExpire(String keys, String value, Long time) {
        redisTemplate.opsForValue().set(keys, value, Duration.ofMillis(time));
    }

    @Override
    public void setRedisExpire(String keys, Object value) {
        setRedisExpire(new String[]{keys}, JSONObject.toJSONString(value));
    }

    @Override
    public void setRedisExpire(String[] keys, Map<String, String> map) {
        String key = getKey(keys);
        setHashVal(key, map);
        expire(key, REDIS_DEF_EXPIRE);
    }

    @Override
    public void setRedisExpire(String keys, Map<String, String> map) {
        setRedisExpire(new String[]{keys}, map);
    }

    @Override
    public void setRedis(String[] keys, String value) {
        set(getKey(keys), value);
    }

    @Override
    public void setRedis(String keys, String value) {
        setRedis(new String[]{keys}, value);
    }

    @Override
    public void setRedis(String[] keys, String[] skeys, String value) {
        String key = getKey(keys);
        String skey = getKey(skeys);
        setHashValKey(key, skey, value);
    }

    @Override
    public void setRedis(String[] keys, String skeys, String value) {
        setRedis(keys, new String[]{skeys}, value);
    }

    @Override
    public void setRedis(String keys, String[] skeys, String value) {
        setRedis(new String[]{keys}, skeys, value);
    }

    @Override
    public void setRedis(String keys, String skeys, String value) {
        setRedis(new String[]{keys}, new String[]{skeys}, value);
    }

    @Override
    public String getRedis(String[] keys) {
        return get(getKey(keys));
    }

    @Override
    public String getRedis(String keys) {
        return getRedis(new String[]{keys});
    }

    @Override
    public String getRedis(String[] keys, String[] skeys) {
        return getHashValStr(getKey(keys), getKey(skeys));
    }

    @Override
    public String getRedis(String[] keys, String skeys) {
        return getRedis(keys, new String[]{skeys});
    }

    @Override
    public String getRedis(String keys, String[] skeys) {
        return getRedis(new String[]{keys}, skeys);
    }

    @Override
    public String getRedis(String keys, String skeys) {
        return getRedis(new String[]{keys}, new String[]{skeys});
    }
    /******************* 新增方法 ↑↑↑↑↑↑ fengyuan ******************************************************************************************/


    /**
     * 将传入的数组转换成一个Key返回 参数 new String[] { list.get(0).getAppid(), sessionId }
     */
    public static String getKey(String[] strs) {
        StringBuffer sBuffer = new StringBuffer();
        for (String strTemp : strs) {
            sBuffer.append(strTemp);
        }
        return sBuffer.toString();
    }
}
